/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Sound from "@react-native-oh-tpl/react-native-sound";
import { songs, Track } from "../PlayList/model";
import { DeviceEventEmitter } from "react-native";

class MusicPlayer {
    private playlist: Track[] = [];
    private currentTrackIndex: number = 0;
    private soundInstance: Sound | null = null;
    private isPlaying: boolean = false;
    private progressInterval: NodeJS.Timeout | null = null;
    private onTrackChangeCallback: ((currentTrack: Track) => void) | null = null;
    setOnTrackChange(callback: (currentTrack: Track) => void) {
        this.onTrackChangeCallback = callback;
    }
    private onStatusChangeCallback: ((isPlaying: boolean) => void) | null = null;
    setOnStatusChange(callback: (isPlaying: boolean) => void) {
        this.onStatusChangeCallback = callback;
    }

    constructor() {
        this.playlist = songs;
        this.currentTrackIndex = 0;
        this.loadTrack(this.currentTrackIndex);
    }

    private loadTrack(index: number) {
        if (this.soundInstance) {
            this.soundInstance.release();
        }

        const track = this.playlist[index];
        if (!track) {
            console.warn('Track not found at index', index);
            return;
        }

        this.soundInstance = new Sound(track.fileName, Sound.MAIN_BUNDLE, (error) => {
            if (error) {
                console.error('Failed to load the track', error);
            }
        });
    }

    play() {
        if (this.soundInstance) {
            this.soundInstance.play(() => {
                this.currentTrackIndex = (this.currentTrackIndex + 1) % this.playlist.length;
                this.loadTrack(this.currentTrackIndex);
                DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
                setTimeout(() => {
                    this.play();
                    this.isPlaying = true;
                    if (this.onStatusChangeCallback) {
                        this.onStatusChangeCallback(this.isPlaying);
                    }
                    if (this.onTrackChangeCallback) {
                        this.onTrackChangeCallback(this.getCurrentTrack()!);
                    }
                }, 2000);
            });
            this.isPlaying = true;
            if (this.onStatusChangeCallback) {
                this.onStatusChangeCallback(this.isPlaying);
            }
        }
    }

    pause() {
        if (this.soundInstance && this.isPlaying) {
            this.soundInstance.pause();
            this.isPlaying = false;
            if (this.onStatusChangeCallback) {
                this.onStatusChangeCallback(this.isPlaying);
            }
        }
    }

    nextTrack() {
        this.currentTrackIndex = (this.currentTrackIndex + 1) % this.playlist.length;
        this.isPlaying = true;
        if (this.onStatusChangeCallback) {
            this.onStatusChangeCallback(this.isPlaying);
        }
        this.loadTrack(this.currentTrackIndex);
        if (this.onTrackChangeCallback) {
            this.onTrackChangeCallback(this.getCurrentTrack()!);
        }
        DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
        setTimeout(() => {
            this.play();
        }, 2000);
    }

    previousTrack() {
        this.currentTrackIndex =
            (this.currentTrackIndex - 1 + this.playlist.length) % this.playlist.length;
        this.isPlaying = true;
        if (this.onStatusChangeCallback) {
            this.onStatusChangeCallback(this.isPlaying);
        }
        this.loadTrack(this.currentTrackIndex);
        if (this.onTrackChangeCallback) {
            this.onTrackChangeCallback(this.getCurrentTrack()!);
        }
        DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
        setTimeout(() => {
            this.play();
        }, 2000);
    }

    playTrackByIndex(index: number) {
        if (index < 0 || index >= this.playlist.length) {
            console.warn('Invalid track index:', index);
            return;
        }
        this.currentTrackIndex = index;
        this.loadTrack(index);
        this.isPlaying = true;
        if (this.onStatusChangeCallback) {
            this.onStatusChangeCallback(this.isPlaying);
        }
        if (this.onTrackChangeCallback) {
            this.onTrackChangeCallback(this.getCurrentTrack()!);
        }
        DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
        setTimeout(() => {
            this.play();
        }, 2000);
    }

    getCurrentStatus() {
        return this.isPlaying;
    }

    getCurrentTrack(): Track | null {
        return this.playlist[this.currentTrackIndex] || null;
    }

    setCurrentTime(value: number) {
        if (this.soundInstance) {
            this.soundInstance.setCurrentTime(value)
        }
    }

    onProgress(callback: (currentTime: number, duration: number) => void) {
        if (!this.soundInstance) {
            return;
        }

        this.clearProgressInterval();
        this.progressInterval = setInterval(() => {
            this.soundInstance?.getCurrentTime((currentTime) => {
                const duration = this.soundInstance?.getDuration() || 0;
                callback(currentTime, duration);
            });
        }, 500);
    }

    private clearProgressInterval() {
        if (this.progressInterval) {
            clearInterval(this.progressInterval);
            this.progressInterval = null;
        }
    }

    release() {
        this.onTrackChangeCallback = null;
        this.onStatusChangeCallback = null;
    }
}

const musicPlayer = new MusicPlayer();

export default musicPlayer;
